package nz.ac.massey.doi_information_extractor.parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang3.StringEscapeUtils;

import nz.ac.massey.doi_information_extractor.data.Author;
import nz.ac.massey.doi_information_extractor.data.AuthorList;
import nz.ac.massey.doi_information_extractor.data.Publication;
public class ParserEngine implements ParserEngineInterface {

	private Publication result;

	public Publication getInformationFromDOI(String doi)throws PublicationNotFoundException, IOException {

		result = new Publication();

		if(!test2()){
			throw new IOException("Error connecting to internet.");
		}

		result.setDoi(doi);
		ExecutorService threadPool = Executors.newFixedThreadPool(7);
		ArrayList<Future<Publication>> futureList = new ArrayList<Future<Publication>>();

		// Place Plugins here and add them to the threadPool
		// Plugin priority works by the first having the highest precedence over
		// the preceding

		Callable<Publication> scienceDirectExportPlugin = new ScienceDirectExportPlugin(
				doi);
		Future<Publication> futureScienceDirectExportResult = threadPool
				.submit(scienceDirectExportPlugin);
		futureList.add(futureScienceDirectExportResult);

		Callable<Publication> scienceDirectPlugin = new ScienceDirectPlugin(doi);
		Future<Publication> futureScienceDirectResult = threadPool
				.submit(scienceDirectPlugin);
		futureList.add(futureScienceDirectResult);

		Callable<Publication> springerPlugin = new SpringerPlugin(doi);
		Future<Publication> futureSpringerResult = threadPool
				.submit(springerPlugin);
		futureList.add(futureSpringerResult);

		Callable<Publication> springerExportPlugin = new SpringerExportPlugin(doi);
		Future<Publication> futurespringerExportResult = threadPool.submit(springerExportPlugin);
		futureList.add(futurespringerExportResult);

		Callable<Publication> scopusPlugin = new SCOPUSPlugin(doi);
		Future<Publication> futureSCOPUSResult = threadPool.submit(scopusPlugin);
		futureList.add(futureSCOPUSResult);

		Callable<Publication> bibsonomyPlugin = new BibsonomyPlugin(doi);
		Future<Publication> futureBibsonomyResult = threadPool.submit(bibsonomyPlugin);
		futureList.add(futureBibsonomyResult);

		Callable<Publication> crossrefPlugin = new CrossrefPlugin(doi);
		Future<Publication> futureCrossrefResult = threadPool.submit(crossrefPlugin);
		futureList.add(futureCrossrefResult);

		// Wait for threads to finish and get collate results
		for (int index = 0; index < futureList.size(); index++) {
			try {
				addToResult(futureList.get(index).get());
			} catch (InterruptedException e) {
				continue;
			} catch (ExecutionException e) {
				continue;
			}catch (Exception e){
				continue;
			}
		}

		if (resultNull()) {
			throw new PublicationNotFoundException("Publication not found");
		}

		return result;
	}

	private boolean test2(){
	    try {
	        String urlName = "http://www.google.com";

	        URL url = new URL(urlName);
	        URLConnection connection = url.openConnection();

	        connection.connect();

	        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

	        // read first ten lines of contents

	        StringBuilder site = new StringBuilder();
	        String line;
	        int n = 1;
	        while ((line = in.readLine()) != null && n <= 10) {
	          site.append(line);
	          n++;
	        }
	      } catch (IOException exception) {
	        return false;
	      }
	      return true;
	}

	private boolean resultNull() {
		if (!result.getDescription().equals(""))
			return false;

		if (!result.getPublicationType().equals(""))
			return false;

		if (!result.getPageNumbers().equals(""))
			return false;

		if (!result.getPublicationTitle().equals(""))
			return false;

		if (!result.getVolumeNumber().equals(""))
			return false;

		if (!result.getArticleTitle().equals(""))
			return false;

		if (!result.getDate().equals(""))
			return false;

		if (!result.getUrl().equals(""))
			return false;

		if (!result.getIssn().equals(""))
			return false;

		// This ensures that even if the Authors field has authors, a subsequent
		// entry with organisation information will supercede it.
		// It assumes that a source that is accurate enough to give
		// organisations will be trustworthy.
		if (result.getAuthors().size() > 0)
			return false;

		if (!result.getPublisher().equals(""))
			return false;

		if (!result.getKeywords().equals(""))
			return false;

		if (!result.getConferenceLocation().equals(""))
			return false;

		if (!result.getConferenceDates().equals(""))
			return false;

		if (!result.getPublisherLocation().equals(""))
			return false;

		if (!result.getEditors().equals(""))
			return false;

		if (!result.getEdition().equals(""))
			return false;

		if (!result.getJournalNumber().equals(""))
			return false;

		return true;
	}

	/**
	 * Translates html character entity references to java escaped unicode
	 * characters.
	 *
	 * @param publication
	 *            The publication to parse.
	 */
	

	/**
	 * Adds the fields of a publication to the result publication It's important
	 * to note that the text fields can either be null or "". Either value
	 * refers to an empty field.
	 *
	 * @param publication
	 *            The publication to add to the result
	 */
	private void addToResult(Publication publication) {
		if (result.getDescription().equals(""))
			result.setDescription(publication.getDescription());

		if (result.getPublicationType().equals(""))
			result.setPublicationType(publication.getPublicationType());

		if (result.getPageNumbers().equals(""))
			result.setPageNumbers(publication.getPageNumbers());

		if (result.getPublicationTitle().equals(""))
			result.setPublicationTitle(publication.getPublicationTitle());

		if (result.getVolumeNumber().equals(""))
			result.setVolumeNumber(publication.getVolumeNumber());

		if (result.getArticleTitle().equals(""))
			result.setArticleTitle(publication.getArticleTitle());

		if (result.getDate().equals(""))
			result.setDate(publication.getDate());

		if (result.getUrl().equals(""))
			result.setUrl(publication.getUrl());

		if (result.getIssn().equals(""))
			result.setIssn(publication.getIssn());

		// This ensures that even if the Authors field has authors, a subsequent
		// entry with organisation information will supersede it.
		// It assumes that a source that is accurate enough to give
		// organisations will be trustworthy.
		if (result.getAuthors().size() == 0
				&& publication.getAuthors().size() > 0)
			result.setAuthors(publication.getAuthors());

		if (result.getAuthors().size() != 0
				&& publication.getAuthors().size() != 0
				&& !publication.getAuthors().get(0).getOrganisation()
						.equals(""))
			result.setAuthors(publication.getAuthors());

		if (result.getPublisher().equals(""))
			result.setPublisher(publication.getPublisher());

		if (result.getKeywords().equals(""))
			result.setKeywords(publication.getKeywords());

		if (result.getConferenceLocation().equals(""))
			result.setConferenceLocation(publication.getConferenceLocation());

		if (result.getConferenceDates().equals(""))
			result.setConferenceDates((publication.getConferenceDates()));

		if (result.getPublisherLocation().equals(""))
			result.setPublisherLocation(publication.getPublisherLocation());

		if (result.getEditors().equals(""))
			result.setEditors(publication.getEditors());

		if (result.getEdition().equals(""))
			result.setEdition(publication.getEdition());

		if (result.getJournalNumber().equals(""))
			result.setJournalNumber(publication.getJournalNumber());
	}
}
